﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.Net;
using System.Text.RegularExpressions;

namespace Lcsoft.UrlRewriter.Utilities
{
	/// <summary>
	/// 表示 IP 地址范围。
	/// </summary>
	public sealed class IPRange
	{
		/// <summary>
		/// 初始化 <see cref="IPRange"/> 类的新实例。
		/// </summary>
		/// <param name="address">一个 <see cref="IPAddress"/>。</param>
		public IPRange(IPAddress address)
		{
			this.MinimumAddress = address;
			this.MaximumAddress = address;
		}

		/// <summary>
		/// 初始化 <see cref="IPRange"/> 类的新实例。
		/// </summary>
		/// <param name="minimumAddress">取值较小的 IP 地址。</param>
		/// <param name="maximumAddress">取值较大的 IP 地址。</param>
		public IPRange(IPAddress minimumAddress, IPAddress maximumAddress)
		{
			if (Compare(minimumAddress, maximumAddress) == -1)
			{
				this.MinimumAddress = minimumAddress;
				this.MaximumAddress = maximumAddress;
			}
			else
			{
				this.MinimumAddress = maximumAddress;
				this.MaximumAddress = minimumAddress;
			}
		}

		/// <summary>
		/// 获取 <see cref="IPRange"/> 对象中取值较小的 IP 地址。
		/// </summary>
		public IPAddress MinimumAddress { get; private set; }

		/// <summary>
		/// 获取 <see cref="IPRange"/> 对象中取值较大的 IP 地址。
		/// </summary>
		public IPAddress MaximumAddress { get; private set; }

		/// <summary>
		/// 解析指定字符串，如果可能则返回一个 <see cref="IPRange"/> 对象。
		/// </summary>
		/// <param name="pattern">要解析的字符串。</param>
		/// <returns>一个 <see cref="IPRange"/> 对象。</returns>
		/// <remarks>
		/// ddd.ddd.ddd.ddd - single IP address
		/// ddd.ddd.ddd.* - class C range
		/// ddd.ddd.* - class B range
		/// ddd.* - class A range
		/// ddd.ddd.ddd.ddd - ccc.ccc.ccc.ccc - specific range
		/// </remarks>
		public static IPRange Parse(string pattern)
		{
			pattern = Regex.Replace(pattern, @"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\.\*", @"$1.0-$1.255");
			pattern = Regex.Replace(pattern, @"([0-9]{1,3}\.[0-9]{1,3})\.\*", @"$1.0.0-$1.255.255");
			pattern = Regex.Replace(pattern, @"([0-9]{1,3})\.\*", @"$1.0.0.0-$1.255.255.255");

			var parts = pattern.Split('-');

			return parts.Length > 1 ? new IPRange(IPAddress.Parse(parts[0].Trim()), IPAddress.Parse(parts[1].Trim())) : new IPRange(IPAddress.Parse(pattern.Trim()));
		}

		/// <summary>
		/// 确定指定的 IP 地址是否包含于当前的 IP 地址范围之内。
		/// </summary>
		/// <param name="address">一个 <see cref="IPAddress"/>。</param>
		/// <returns>如果 <paramref name="address"/> 包含在当前的 IP 地址范围内，则返回 true，否则返回 false。</returns>
		public bool InRange(IPAddress address) { return Compare(this.MinimumAddress, address) <= 0 && Compare(address, this.MaximumAddress) <= 0; }

		/// <summary>
		/// 比较两个 IP 地址。
		/// </summary>
		/// <param name="left">要比较的第一个 IP 地址。</param>
		/// <param name="right">要比较的第二个 IP 地址。</param>
		/// <returns>如果 <paramref name="left"/> 等于 <paramref name="right"/> 则返回 0；如果 <paramref name="left"/> 大于 <paramref name="right"/> 则返回值大于 0；如果 <paramref name="left"/> 小于 <paramref name="right"/> 则返回值小于 0。</returns>
		public static int Compare(IPAddress left, IPAddress right)
		{
			if (left == null) throw new ArgumentNullException("left");
			if (right == null) throw new ArgumentNullException("right");

			var leftBytes = left.GetAddressBytes();
			var rightBytes = right.GetAddressBytes();

			if (leftBytes.Length != rightBytes.Length) throw new ArgumentOutOfRangeException(MessageProvider.FormatString(Message.AddressesNotOfSameType));

			for (var i = 0; i < leftBytes.Length; i++)
			{
				if (leftBytes[i] < rightBytes[i]) return -1;
				if (leftBytes[i] > rightBytes[i]) return 1;
			}

			return 0;
		}
	}
}
